package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.ItemService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * projectName: gmall
 *
 * @author: 陈鹏
 * time: 2022/9/25 16:09 星期日
 * description: 提供给商品详情微服务内部调用的接口类
 */
@Service
@Log4j2
public class ItemServiceImpl implements ItemService {

    @Resource
    private SkuInfoMapper skuInfoMapper;
    /**
     * 根据skuId查询sku信息
     *
     * @param skuId
     * @return
     */
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        return skuInfoMapper.selectById(skuId);
    }

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;
    /**
     * 根据skuId查询skuInfo信息 (加入了redis缓存)
     *
     * @param skuId
     * @return
     */
    @Override
    public SkuInfo getSkuInfoByRedisOrMysql(Long skuId) {
        //从redis中获取数据 key为skuInfo+skuId+info
        SkuInfo skuInfo =
                (SkuInfo) redisTemplate.opsForValue().get("skuInfo:" + skuId + ":info");
        //如果redis中有 直接返回
        if(skuInfo != null){
            return skuInfo;
        }
        //如果redis中没有 此时需要去mysql中查询 获取锁是为了防止高并发击穿mysql服务器
        //锁的key为skuInfo+skuId+lock
        RLock lock = redissonClient.getLock("skuInfo:" + skuId + ":lock");
        //加锁成功后进入查询
        try {
            if(lock.tryLock(100,100, TimeUnit.SECONDS)){
                try {
                    //查询数据库
                    skuInfo = skuInfoMapper.selectById(skuId);
                    //判断
                    if(skuInfo == null || skuInfo.getId() == null){
                        //若查询的skuInfo不存在 造一条空数据放入Redis中
                        skuInfo = new SkuInfo();
                        redisTemplate.opsForValue().set("skuInfo:" + skuId +":info",skuInfo,300,TimeUnit.SECONDS);
                    }else{
                        //数据库有,则将查询的skuInfo放入redis中
                        redisTemplate.opsForValue().set("skuInfo:" + skuId +":info",skuInfo,24*60*60,TimeUnit.SECONDS);
                    }
                    //返回结果
                    return skuInfo;
                }catch (Exception e1){
                        log.error("加锁成功,但是操作出现异常,异常的内容为: " + e1.getMessage());
                }finally {
                    //无论如何都要释放锁
                    lock.unlock();
                }
            }
        }catch (Exception e){
            log.error("加锁失败,出现的异常为:" + e.getMessage());
        }
        return null;
    }

    @Resource
    private BaseCategoryViewMapper baseCategoryViewMapper;
    /**
     * 根据category3Id查询分类信息
     *
     * @param category3Id
     * @return
     */
    @Override
    public BaseCategoryView getBaseCategory(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }

    @Resource
    private SkuImageMapper skuImageMapper;
    /**
     * 根据skuId查询sku图片列表
     *
     * @param skuId
     * @return
     */
    @Override
    public List<SkuImage> getImageList(Long skuId) {
        return skuImageMapper.selectList(
                new LambdaQueryWrapper<SkuImage>()
                        .eq(SkuImage::getSkuId,skuId));
    }

    /**
     * 根据skuId查询价格
     *
     * @param skuId
     * @return
     */
    @Override
    public BigDecimal getPrice(Long skuId) {
        return skuInfoMapper.selectById(skuId).getPrice();
    }

    @Resource
    private SpuSaleAttrMapper spuSaleAttrMapper;
    /**
     * 根据sku和spu的id查询销售属性和值以及标识出当前的sku的值是哪些
     *
     * @param skuId
     * @param spuId
     * @return
     */
    @Override
    public List<SpuSaleAttr> getSpuSaleAttr(Long skuId, Long spuId) {
        return spuSaleAttrMapper.selectSpuSaleAttrBySpuAndSku(skuId,spuId);
    }

    @Resource
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    /**
     * 根据spuId查询所有的销售属性和销售值
     *
     * @param spuId
     * @return
     */
    @Override
    public Map selectSkuValuesList(Long spuId) {
        //查询指定spu的全部销售属性值和id的键值对
        List<Map> maps = skuSaleAttrValueMapper.selectSkuValuesList(spuId);
        //返回结果初始化
        Map result = new ConcurrentHashMap();
        //遍历转换为一个map
        maps.stream().forEach(map -> {
            //获取sku的id
            Object skuId = map.get("sku_id");
            //获取sku对应的销售属性值的组合
            Object valuesId = map.get("values_id");
            //放到一个map中保存
            result.put(valuesId,skuId);
        });
        return result;
    }

    @Resource
    private BaseTrademarkMapper baseTrademarkMapper;
    /**
     * 根据Id查询品牌详情
     *
     * @param id
     * @return
     */
    @Override
    public BaseTrademark getBaseTrademark(Long id) {
        return baseTrademarkMapper.selectById(id);
    }

    @Resource
    private BaseAttrInfoMapper baseAttrInfoMapper;
    /**
     * 根据skuId查询sku的平台属性
     *
     * @param skuId
     * @return
     */
    @Override
    public List<BaseAttrInfo> getBaseAttrInfo(Long skuId) {
        return baseAttrInfoMapper.selectAttrInfoBySkuId(skuId);
    }

    /**
     * 扣减库存
     *
     * @param decountMap
     */
    @Override
    public void decount(Map<String, Object> decountMap) {
        //遍历扣减库存
        decountMap.entrySet().stream().forEach(entry ->{
            /**
             * 超卖问题--->库存混乱问题!!
             */
            //获取商品id
            long skuId = Long.parseLong(entry.getKey());
            //获取扣减的数量
            int num = Integer.parseInt(entry.getValue().toString());
            //扣减库存
            int decount = skuInfoMapper.decount(skuId, num);
            if(decount <= 0){
                throw new RuntimeException("扣减库存失败,下单失败!");
            }
        });
    }

    /**
     * 回滚库存
     *
     * @param rollBackMap
     */
    @Override
    public void rollback(Map<String, Object> rollBackMap) {
        //回滚库存
        rollBackMap.entrySet().stream().forEach(entry ->{
            //获取商品Id
            long skuId = Long.parseLong(entry.getKey());
            //获取商品数量
            int num = Integer.parseInt(entry.getValue().toString());
            //回滚库存
            int i = skuInfoMapper.rollback(skuId, num);
            if(i <= 0 ){
                throw new RuntimeException("回滚库存失败!");
            }
        });
    }
}
